package com.sun.temp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.temp.bean.Material;
import com.sun.temp.bean.Point;
import com.sun.temp.bean.PrdBcdQaPlanresult;
import com.sun.temp.bean.PrdBcdQaPlanresultEx;
import com.sun.temp.bean.Qakansa;
import com.sun.temp.dto.TempDto;
import com.sun.temp.mapper.mapper1.MaterialDao;
import com.sun.temp.mapper.mapper2.PrdBcdQaPlanresultDao;
import com.sun.temp.mapper.mapper2.PrdBcdQaPlanresultExDao;
import com.sun.temp.mapper.mapper3.QakansaDao;
import com.sun.temp.service.MaterialService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.text.DecimalFormat;
import java.util.*;
import java.math.BigDecimal;

@Service
@Slf4j
public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> implements MaterialService {

    @Resource
    private QakansaDao qakansaDao;

    @Resource
    private PrdBcdQaPlanresultDao resultDao;
    @Resource
    private PrdBcdQaPlanresultExDao resultExDao;

    @Override
    public List<Material> queryMaterial() {
        return this.baseMapper.queryMaterial();
    }

    @Override
    public List<Material> queryMaterialByDate(String date) {
        return this.baseMapper.queryMaterialByDate(date);
    }

    @Override
    public List<Material> queryMaterialByGradeAndBatch(String grade,String batch) {
        return this.baseMapper.queryMaterialByGradeAndBatch(grade,batch);
    }

    @Override
    public List<Material>queryMaterialByStatus(Integer status) {
        return this.baseMapper.queryMaterialByStatus(status);
    }

    @Override
    public List<Material> queryBatchByTaskId(Integer id) {
        return this.baseMapper.queryBatchByTaskId(id);
    }

    @Override
    public List<Material> queryMaterialToday() {
        return this.baseMapper.queryMaterialToday();
    }

    @Override
    public List<Material> queryBatchSuccessByTaskId(Integer id) {
        return this.baseMapper.queryBatchSuccessByTaskId(id);
    }

    @Override
    public void insertList(List<Qakansa> qakansas, Integer taskId) {
        for (Qakansa qakansa : qakansas) {
            Material material = new Material();
            material.setBatch(qakansa.getLOT_NO().toString());
            material.setGrade(qakansa.getITM_CD());
//            material.setCreateTime(new Date());
            material.setTaskId(taskId);
            this.baseMapper.insert(material);
        }
    }

    @Override
    public boolean saveAutoMaterial(File path) {
        // 查询待分析的批次
        Material material = this.baseMapper.selectOne(new QueryWrapper<Material>().eq("status", 1));
//        if (null == material) {
//            return false;
//        }

        try {
            Map<Double, Double> map = read(path.getAbsolutePath());

            Set<Double> doubles = map.keySet();
            Double a = findClosestToForty(doubles, 40.0);
            Double b = findClosestToForty(doubles, 80.0);
            Double c = findClosestToForty(doubles, 190.0);
            Double d = findClosestToForty(doubles, 230.0);
            Double e = findClosestToForty(doubles, 220.0);
            Double f = findClosestToForty(doubles, 240.0);
            TempDto tempa = new TempDto();
            tempa.setTemp(a.toString());
            tempa.setTma(map.get(a).toString());
            material.setTempa(tempa);

            TempDto tempb = new TempDto();
            tempb.setTemp(b.toString());
            tempb.setTma(map.get(b).toString());
            material.setTempb(tempb);

            TempDto tempc = new TempDto();
            tempc.setTemp(c.toString());
            tempc.setTma(map.get(c).toString());
            material.setTempc(tempc);

            TempDto tempd = new TempDto();
            tempd.setTemp(d.toString());
            tempd.setTma(map.get(d).toString());
            material.setTempd(tempd);

            // 计算斜率和交叉点
            double xielv1 = calSlope(a, map.get(a), b, map.get(b), map.get((double)0));
            double xielv2 = calSlope(c, map.get(c), d, map.get(d), map.get((double)0));
//            Point jiaodian = findIntersectionPoint(a, map.get(a), b, map.get(b), c, map.get(c), d, map.get(d));
            Point jiaodian = findIntersectionPoint(a, map.get(a), b, map.get(b), e, map.get(e), f, map.get(f));

            material.setStatus(2);
            material.setResulta(xielv1);
            material.setResultb(xielv2);
            material.setResultc(jiaodian.getX());
            // 更新本地MySql数据库
            this.baseMapper.updateById(material);
            // 提交到oracle数据库
            this.insertData(material, xielv1, xielv2, jiaodian.getX(), material.getBatch());

        } catch (Exception e) {
        }
        return true;
    }

    @Override
    public List<Material> queryResultByTaskId(Integer taskId) {
        return this.baseMapper.queryBatchByTaskId(taskId);
    }


    /**
     * 插入线膨胀系数(1)(2)、玻璃化温度
     */
    private void insertData(Material material, double xielv1, double xielv2, double jiaodian, String lot_no) {
        this.inserXieLv1(lot_no,xielv1);
        this.inserXieLv2(lot_no,xielv2);
        this.inserJiaodian(lot_no,jiaodian);
    }

    private void inserXieLv1(String lot_no,double xielv1){

        DecimalFormat decimalFormat = new DecimalFormat("0.0");

        // Oracles数据库查询线膨胀系数1数据
        Qakansa qakansaA = qakansaDao.getByBatchAndItemID(lot_no,"353");
        if (qakansaA == null)
            return;

        // 线膨胀系数(1)正常数据
        PrdBcdQaPlanresult resulta = new PrdBcdQaPlanresult();
        resulta.setBpr_id(UUID.randomUUID().toString());
        resulta.setBpr_itemid("353");
        resulta.setBpr_itemname("线膨胀系数(1)");
        resulta.setBpr_batchno(qakansaA.getLOT_NO());
        resulta.setBpr_result(decimalFormat.format(xielv1));
        resulta.setBpr_qa("MTA");
        resulta.setBpr_qadate(new Date());
        resulta.setBpr_status("1");
        resulta.setBpr_itmcd(qakansaA.getITM_CD());
        resulta.setBpr_inspseq(qakansaA.getINSP_SEQ());
        resulta.setBpr_insptyp(qakansaA.getINSP_KND_TYP());

        // 线膨胀系数(1)异常数据
        PrdBcdQaPlanresultEx resultaEx = new PrdBcdQaPlanresultEx();
        resultaEx.setBpr_id(UUID.randomUUID().toString());
        resultaEx.setBpr_itemid("353");
        resultaEx.setBpr_itemname("线膨胀系数(1)");
        resultaEx.setBpr_batchno(qakansaA.getLOT_NO());
        resultaEx.setBpr_result(decimalFormat.format(xielv1));
        resultaEx.setBpr_qa("MTA");
        resultaEx.setBpr_qadate(new Date());
        resultaEx.setBpr_status("0");
        resultaEx.setBpr_itmcd(qakansaA.getITM_CD());
        resultaEx.setBpr_inspseq(qakansaA.getINSP_SEQ());
        resultaEx.setBpr_insptyp(qakansaA.getINSP_KND_TYP());
        resultaEx.setQuantitative_max(qakansaA.getQUANTITATIVE_MAX() == null?"":qakansaA.getQUANTITATIVE_MAX().toString());
        resultaEx.setQuantitative_min(qakansaA.getQUANTITATIVE_MIN() == null?"":qakansaA.getQUANTITATIVE_MIN().toString());

        this.handleInsert(qakansaA,xielv1,resulta,resultaEx,decimalFormat);
    }

    private void inserXieLv2(String lot_no, double xielv2){

        DecimalFormat decimalFormat = new DecimalFormat("0.0");

        // Oracles数据库查询线膨胀系数2数据
        Qakansa qakansaB = qakansaDao.getByBatchAndItemID(lot_no,"354");
        if (qakansaB == null)
            return;

        // 线膨胀系数(2)正常数据
        PrdBcdQaPlanresult resultb = new PrdBcdQaPlanresult();
        resultb.setBpr_id(UUID.randomUUID().toString());
        resultb.setBpr_itemid("354");
        resultb.setBpr_itemname("线膨胀系数(2)");
        resultb.setBpr_batchno(qakansaB.getLOT_NO());
        resultb.setBpr_result(decimalFormat.format(xielv2));
        resultb.setBpr_qa("MTA");
        resultb.setBpr_qadate(new Date());
        resultb.setBpr_status("1");
        resultb.setBpr_itmcd(qakansaB.getITM_CD());
        resultb.setBpr_inspseq(qakansaB.getINSP_SEQ());
        resultb.setBpr_insptyp(qakansaB.getINSP_KND_TYP());

        // 线膨胀系数(2)异常数据
        PrdBcdQaPlanresultEx resultbEx = new PrdBcdQaPlanresultEx();
        resultbEx.setBpr_id(UUID.randomUUID().toString());
        resultbEx.setBpr_itemid("354");
        resultbEx.setBpr_itemname("线膨胀系数(2)");
        resultbEx.setBpr_batchno(qakansaB.getLOT_NO());
        resultbEx.setBpr_result(decimalFormat.format(xielv2));
        resultbEx.setBpr_qa("MTA");
        resultbEx.setBpr_qadate(new Date());
        resultbEx.setBpr_status("0");
        resultbEx.setBpr_itmcd(qakansaB.getITM_CD());
        resultbEx.setBpr_inspseq(qakansaB.getINSP_SEQ());
        resultbEx.setBpr_insptyp(qakansaB.getINSP_KND_TYP());
        resultbEx.setQuantitative_max(qakansaB.getQUANTITATIVE_MAX() == null?"":qakansaB.getQUANTITATIVE_MAX().toString());
        resultbEx.setQuantitative_min(qakansaB.getQUANTITATIVE_MIN() == null?"":qakansaB.getQUANTITATIVE_MIN().toString());

        this.handleInsert(qakansaB,xielv2,resultb,resultbEx,decimalFormat);
    }

    private void inserJiaodian(String lot_no,double jiaodian){

        DecimalFormat decimalFormat = new DecimalFormat("0");

        // Oracles数据库查询玻璃化温度数据
        Qakansa qakansaC = qakansaDao.getByBatchAndItemID(lot_no,"355");
        if (qakansaC == null)
            return;

        // 玻璃化温度正常数据
        PrdBcdQaPlanresult resultc = new PrdBcdQaPlanresult();
        resultc.setBpr_id(UUID.randomUUID().toString());
        resultc.setBpr_itemid("355");
        resultc.setBpr_itemname("玻璃化温度");
        resultc.setBpr_batchno(qakansaC.getLOT_NO());
        resultc.setBpr_result(decimalFormat.format(jiaodian));
        resultc.setBpr_qa("MTA");
        resultc.setBpr_qadate(new Date());
        resultc.setBpr_status("1");
        resultc.setBpr_itmcd(qakansaC.getITM_CD());
        resultc.setBpr_inspseq(qakansaC.getINSP_SEQ());
        resultc.setBpr_insptyp(qakansaC.getINSP_KND_TYP());

        // 玻璃化温度异常数据
        PrdBcdQaPlanresultEx resultcEx = new PrdBcdQaPlanresultEx();
        resultcEx.setBpr_id(UUID.randomUUID().toString());
        resultcEx.setBpr_itemid("355");
        resultcEx.setBpr_itemname("玻璃化温度");
        resultcEx.setBpr_batchno(qakansaC.getLOT_NO());
        resultcEx.setBpr_result(decimalFormat.format(jiaodian));
        resultcEx.setBpr_qa("MTA");
        resultcEx.setBpr_qadate(new Date());
        resultcEx.setBpr_status("0");
        resultcEx.setBpr_itmcd(qakansaC.getITM_CD());
        resultcEx.setBpr_inspseq(qakansaC.getINSP_SEQ());
        resultcEx.setBpr_insptyp(qakansaC.getINSP_KND_TYP());
        resultcEx.setQuantitative_max(qakansaC.getQUANTITATIVE_MAX() == null?"":qakansaC.getQUANTITATIVE_MAX().toString());
        resultcEx.setQuantitative_min(qakansaC.getQUANTITATIVE_MIN() == null?"":qakansaC.getQUANTITATIVE_MIN().toString());

        this.handleInsert(qakansaC,jiaodian,resultc,resultcEx,decimalFormat);
    }

    private void handleInsert(Qakansa qakansa,double mesure,PrdBcdQaPlanresult result, PrdBcdQaPlanresultEx resultEx,DecimalFormat decimalFormat){
        BigDecimal mesureDec = new BigDecimal(decimalFormat.format(mesure));
        if(qakansa.getQUANTITATIVE_MIN() == null && qakansa.getQUANTITATIVE_MAX() != null){
            //1、如果规格参数quantitative_max有数值， 但quantitative_min为null或空，则结果值必须小于等于quantitative_max
            if (mesureDec.compareTo(qakansa.getQUANTITATIVE_MAX()) >0){
                resultExDao.insert(resultEx);
            }else {
                resultDao.insert(result);
            }
        }else if(qakansa.getQUANTITATIVE_MIN() != null && qakansa.getQUANTITATIVE_MAX() == null){
            //2、如果规格参数quantitative_max为null或空， 但quantitative_min有数值，则结果值必须大于等于quantitative_min，否则写入PRD_BCD_QA_PLANRESULT_EX异常记录表
            if (mesureDec.compareTo(qakansa.getQUANTITATIVE_MIN()) <0){
                resultExDao.insert(resultEx);
            }else {
                resultDao.insert(result);
            }
        }else if(qakansa.getQUANTITATIVE_MIN() == null && qakansa.getQUANTITATIVE_MAX() == null){
            resultExDao.insert(resultEx);
        }
        else if(qakansa.getQUANTITATIVE_MIN().compareTo(BigDecimal.valueOf(99999)) == 0 || qakansa.getQUANTITATIVE_MAX().compareTo(BigDecimal.valueOf(99999)) == 0){
            // 4、如果规格参数quantitative_max=99999 或quantitative_min=99999， 则可以录入任意数值
            resultDao.insert(result);
        }else{
            if (mesureDec.compareTo(qakansa.getQUANTITATIVE_MIN())< 0 || mesureDec.compareTo(qakansa.getQUANTITATIVE_MAX()) >0){
                resultExDao.insert(resultEx);
            }else {
                resultDao.insert(result);
            }
        }
    }


    /**
     * 读取txt文件
     *
     * @param filepath
     * @return
     */
    private static Map<Double, Double> read(String filepath) {

        Map<Double, Double> map = new HashMap<>();

        File file = new File(filepath);
        BufferedReader reader = null;
        String tempString = null;

        try {
            reader = new BufferedReader(new FileReader(file));
            while ((tempString = reader.readLine()) != null) {
                // 读取高度
                if ("<Sample Geometry>".equals(tempString)) {
                    String length = reader.readLine();
                    map.put((double) 0, Double.parseDouble(length.split(" ")[1]));
                    break;
                }
            }

            while ((tempString = reader.readLine()) != null) {
                // 取数从<Raw Data>行+2 开始
                if ("<Raw Data>".equals(tempString)) {
                    break;
                }
            }

            // 跳过两行，分别是title和unit
            reader.readLine();
            reader.readLine();

            while ((tempString = reader.readLine()) != null) {
                // 读到空行跳出
                if (StringUtils.isEmpty(tempString.trim())) {
                    break;
                }

                // No. Time Temp. TMA Load DTMA
                // 0 5 25.1477 0.012538 -10003.4 0.0998497
                // 取Temp和TMA
                Double temp = Double.parseDouble(tempString.split(" ")[2]);
                Double tma = Double.parseDouble(tempString.split(" ")[3]);
                map.put(temp, tma);
            }

            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return map;
    }

    /**
     * 按目标值找最相近的数据
     *
     * @param numbers
     * @param target
     * @return
     */
    private static double findClosestToForty(Set<Double> numbers, double target) {
        double closest = 0.0;
        double minDistance = Double.POSITIVE_INFINITY;

        for (double number : numbers) {
            double distance = Math.abs(number - target);
            if (distance < minDistance) {
                minDistance = distance;
                closest = number;
            }
        }

        return closest;
    }

    /**
     * 计算斜率
     *
     * @return
     */
    private static double calSlope(double x1, double y1, double x2, double y2, double length) {
        return (((y2 - y1) / (x2 - x1)) / length) * 100 ;
    }

    /**
     * 获取两条线的交点
     *
     * @return
     */
    private static Point findIntersectionPoint(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {

        double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);

        if (d == 0) {
            return null; // 两条线段平行或共线，没有交点
        }

        double px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
        double py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;

        return new Point(px, py);
    }
}
